#include <iostream>
#include <string.h>
using namespace std;
class CowString{
public:
    CowString()
        //数据前面分配四个字节用来存储引用计数
        //指针+4偏移到数据的位置
        :_pstr(new char[5]()+4)
    {
        cout << "cowString()"<<endl;
        *(int *)(_pstr -4) = 1;
    }
    //拷贝构造函数
    //主要作用是将C风格的字符串转换成CowString类型
    CowString(const char * pstr)
        :_pstr(new char[strlen(pstr) +5]+4)
    {
        cout<<"CowString(const char *)"<<endl;
        strcpy(_pstr,pstr);
        *(int *)(_pstr -4) = 1;
    }
    //浅拷贝
    //增加引用计数
    CowString(const CowString & rhs)
        :_pstr(rhs._pstr)
    {
        cout<<"CowString(const CowString &)"<<endl;
        ++*(int *)(_pstr -4);
    }
    //赋值运算函数
    CowString & operator=(const CowString & rhs){
        cout<<"CowString & operator=(const CowString &)"<<endl;
        //不是自赋值，如果是字符值就没必要改动引用计数
        if(this != &rhs){
            if(--*(int *)(_pstr -4) == 0){
                //如果引用计数为0了就要销毁释放
                delete  [] (_pstr -4);
            }
            //将指针指向新的赋值内存
            _pstr = rhs._pstr;
            ++*(int *)(_pstr -4);
        }
        return *this;
    }
    ~CowString(){
        cout<<"~CowString()"<<endl;
        if(--*(int *)(_pstr -4) == 0){
            delete  [](_pstr -4);
        }
    }
    const char * c_str()const{
        return _pstr;
    }

    friend ostream & operator <<(ostream &os,CowString & rhs);
    //重载[]运算符
    size_t refcount()const{
        return *(int *)(_pstr -4);
    }
    size_t size() const{
        return strlen(_pstr);
    }
    void init_refcount(){
        *(int *)(_pstr -4 ) = 1;
    }
    int increase_refcount(){
        return ++*(int *)(_pstr -4);
    }
    int decrease_refcount(){
        return --*(int *)(_pstr - 4);
    }

private:
    class CharProxy{
      public:
          CharProxy(CowString & CowString,size_t index)
              :_self(CowString)
              ,_index(index)
        {}
          char & operator=(const char & c){
              if(_index <= _self.size()){
                  if(_self.refcount()>1){
                      //如果引用计数大于1
                      //先进行深拷贝，再进行写操作
                      char * temp = new char[_self.size()+5]()+4;
                      strcpy(temp,_self._pstr);
                      //减少原本的引用计数
                      _self.decrease_refcount();
                      //指向新的内存空间
                      _self._pstr = temp;
                      //初始化新的引用计数
                      _self.init_refcount();
                  }
                  _self._pstr[_index] = c;
                  return _self._pstr[_index];
              }else{
                  static char nullchar = '\0';
                  return nullchar;
              }
          }
    friend ostream & operator<<(ostream &os,const CharProxy &rhs);
      private:
          CowString & _self;
          size_t _index;
    };
    char * _pstr;
public:
    CharProxy  operator[](size_t index){
        return CharProxy(*this,index);
    }
friend ostream & operator<<(ostream & os,const CharProxy & rhs);
};
ostream & operator<<(ostream & os,CowString & rhs){
    if(rhs._pstr){
        os<<rhs._pstr;
    }
    return os;
}
ostream & operator<<(ostream & os,const CowString::CharProxy & rhs){
    os<<rhs._self._pstr[rhs._index];
    return os;
}

void test(){
    //s1和s3共享同一片空间，如果修改了s1，s3也会跟着被修改
    //读操作，直接进行，写操作应该让s1重新申请一片空间去修改不应该修改
    //s3的内容i,运算符重载需要自定义类，所以创建一个内部类重载<<和=
    //只要引用计数大于1说明这个字符串需要拷贝
    CowString s1("Hello World");
    CowString s3 = s1;
    cout << s1[0]<<endl;
    cout<< s3[0]<<endl;
    s1[0] = 'h';
    cout<<"================="<<endl;
    cout<<s1[0]<<endl;
    cout<<s3[0]<<endl;
}
int main()
{
    test();
    return 0;
}

